﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

using LowLevelGraphics.Types.Interval;
using LowLevelGraphics;
using LowLevelGraphics.Filter;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Gray Color
    /// </summary>
    public class GrayAndColor2 : BaseForeBackgroundColorFilter
    {
        protected Color[] m_aColor = Definitions.KnownColors;
        protected int m_RG = 40;
        protected int m_RB = 40;
        protected int m_GB = 40;
        protected MULTITHRESHOLD_MODE m_MULTITHRESHOLD_MODE = MULTITHRESHOLD_MODE.FOREGROUND_COLOR;
        protected bool m_bUseMask = false;

        /// <summary>
        /// default constructor
        /// </summary>
        public GrayAndColor2()
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_grayColor"></param>
        internal GrayAndColor2(GrayAndColor2 _grayColor)
        {
            this.m_RG = _grayColor.m_RG;
            this.m_RB = _grayColor.m_RB;
            this.m_GB = _grayColor.m_GB;
            this.m_MULTITHRESHOLD_MODE = _grayColor.m_MULTITHRESHOLD_MODE;
            this.m_bUseMask = _grayColor.m_bUseMask;
        }

        /// <summary>
        /// execute this instance
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            int nHeight = _bitmap.Height;
            int nWidth = _bitmap.Width;

            // calculate difference between each color in the selected pixel.
            int nDiffRG = 0;
            int nDiffRB = 0;
            int nDiffGB = 0;

            // setup color acceptance range
            int nRGlow = 0;
            int nRGhigh = 0;
            int nRBlow = 0;
            int nRBhigh = 0;
            int nGBlow = 0;
            int nGBhigh = 0;

            nRGlow = nDiffRG - m_RG;    // user pixel value range
            nRGhigh = nDiffRG + m_RG;

            nRBlow = nDiffRB - m_RB;
            nRBhigh = nDiffRB + m_RB;

            nGBlow = nDiffGB - m_GB;
            nGBhigh = nDiffGB + m_GB;

            int nCount = m_aColor.Length;
            for (int y = 0; y < nHeight; ++y)
            {
                for (int x = 0; x < nWidth; ++x)
                {
                    // if the pixel color ratio is within ratio of selected area,
                    // not in separate statements because we don't care which
                    // evaluation is not true
                    Color color2 = _bitmap.GetPixel(x, y);
                    int r = color2.R;
                    int g = color2.G;
                    int b = color2.B;

                    for (int i = 0; i < nCount; i++)
                    {
                        // Note: Do not use absolute value because each pixel in the image
                        // code below is checked in the same manner.
                        nDiffRG = m_aColor[i].R - m_aColor[i].G;
                        nDiffRB = m_aColor[i].R - m_aColor[i].B;
                        nDiffGB = m_aColor[i].G - m_aColor[i].B;

                        bool bConditionFulfilled =
                            r - g > nRGlow && r - g < nRGhigh &&
                            r - b > nRBlow && r - b < nRBhigh &&
                            g - b > nGBlow && g - b < nGBhigh;

                        if (bConditionFulfilled)
                        {
                            //p[2] = p[1] = p[0] = (byte)(.299 * p[2] + .587 * p[1] + .114 * p[0]);
                            int nGray = (byte)(r * .299) + (byte)(g * .587) + (byte)(b * .114);

                            if (m_bUseMask)
                            {
                                switch (m_MULTITHRESHOLD_MODE)
                                {
                                    case MULTITHRESHOLD_MODE.FOREGROUND_COLOR:
                                        _bitmap.SetPixel(x, y, bConditionFulfilled ? m_ColorForeground : m_ColorBackground);
                                        break;

                                    case MULTITHRESHOLD_MODE.FOREGROUND_MASK:
                                        _bitmap.SetPixel(x, y, bConditionFulfilled ? color2 : m_ColorBackground);
                                        break;

                                    case MULTITHRESHOLD_MODE.BACKGROUND_MASK:
                                        _bitmap.SetPixel(x, y, bConditionFulfilled ? m_ColorBackground : color2);
                                        break;

                                    case MULTITHRESHOLD_MODE.BACKGROUND_COLOR:
                                        _bitmap.SetPixel(x, y, bConditionFulfilled ? m_ColorBackground : m_ColorForeground);
                                        break;
                                }
                            }
                            else
                            {
                                _bitmap.SetGrayPixel(x, y, nGray);
                            }
                        }
                    }
                }
            }
            return _bitmap;
        }

        /// <summary>
        /// Gets or sets tolerance color
        /// </summary>
        public Color[] ToleranceColor
        {
            get { return m_aColor; }
            set { m_aColor = value; }
        }

        /// <summary>
        /// Gets or sets RG
        /// </summary>
        public int RG
        {
            get { return m_RG; }
            set { m_RG = value; }
        }

        /// <summary>
        /// Gets or sets RB
        /// </summary>
        public int RB
        {
            get { return m_RB; }
            set { m_RB = value; }
        }

        /// <summary>
        /// Gets or sets GB
        /// </summary>
        public int GB
        {
            get { return m_GB; }
            set { m_GB = value; }
        }

        /// <summary>
        /// clone this instance
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new GrayAndColor2(this);
        }
    }
}
